package p.ithorns.framework.common.tree;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * TreeHelper
 * 树构建辅助工具
 *
 * @author liuhaitao
 * @version 1.0
 * @date 2022/3/16 17:17
 */
public final class TreeHelper {

    /**
     * 构建树结构列表
     *
     * 首先数据对象本身需要支持父子结构(包含ID和父ID)，实现{@link Treelizable}接口
     * 然后使用该方法前将数据对象的列表转换成节点({@link TreeNode})列表，
     * 通过对每个节点迭代递归设置子节点列表，最终构建成树节点列表结构
     *
     * @param nodes -节点列表
     * @param <E>   -数据对象类型，需实现{@link Treelizable}
     * @return List<TreeNode>
     */
    public static <E extends Treelizable> List<TreeNode> build(final String rootId,
                                                               Set<TreeNode> nodes) {
        return nodes.stream()
                .map(node -> {
                    if (rootId.equals(node.getPid())) {
                        return getChildren(nodes, node);
                    }
                    return null;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 递归构建节点树
     *
     * @param nodes   -节点列表
     * @param current -当前节点
     * @param <E>     -数据对象类型
     * @return TreeNode 返回当前节点的树
     */
    private static <E extends Treelizable> TreeNode getChildren(Set<TreeNode> nodes,
                                                                TreeNode current) {
        if (null == current.getChildren()) {
            current.setChildren(new ArrayList<E>());
        }
        // 遍历列表
        for (TreeNode node : nodes) {
            if (current.getId().equals(node.getPid())) {
                current.add(getChildren(nodes, node));
            }
        }

        // 当前层级
        final Serializable curId = current.getId();
        final int level = current.getLevel();

        List<TreeNode> children = current.getChildren();
        for (TreeNode e : children) {
            e.setLevel(level + 1);
            current.add(e);
        }

        return current;
    }

    /**
     * 数据对象转节点对象
     *
     * @param e        -数据对象
     * @param parentId -父ID
     * @param level    -层级
     * @param <E>      -数据对象类型
     * @return TreeNode 树节点
     */
    public static <E extends Treelizable> TreeNode toNode(E e, Serializable parentId, int level) {
        TreeNode<E> node = new TreeNode<>();
        node.setId(e.id());
        node.setPid(parentId);
        node.setLabel(e.label());
        node.setLevel(level);
        node.setType(e.type());
        node.setExt(e);
        node.calKey();
        return node;
    }
}
